<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue3.js"></script>
</head>

<body>
    <div id="app">
        <div ref="root"></div>
    </div>
</body>
<script>
    import { ref, computed, reactive, toRefs, toRef, watch, watchEffect, readonly } from 'vue'
    export default {
        name: 'demo',
        props: ["title"],
        setup(props) {
            // vue3中响应式基于ref(初始值)构建响应式数据（状态）
            // 返回RefImpl对象
            // 具备value属性可以获取和设置状态值
            // 而且value属性进行了set/get数据劫持[Object.defineProperty]
            // 在模板试图中渲染的时候，我们无需RefImpl.value。因为自动渲染的就是他的value值，但是在js中使用的时候必须带上value
            let supNum = ref(10)
            let oppNum = ref(5)
            return {
                supNum,
                oppNum
            }

            // computed 传入一个getter函数，返回computedRefImpl对象，和RefImpl对象类似，都是操作他的value属性
            // 这样获取到的值是只读的，当我们尝试修改的时候，报警告
            const count = ref(1)
            const plusOne = computed(() => count.value + 1)
            // 或者传入一个get set函数
            const plustwo = computed({
                get: () => count.value + 1,
                set: (value) => {
                    count.value = value + 1
                }
            })

            // 普通方法直接写
            const change = () => {

            }


            // reactive 响应式方案。
            // 基于es6中的Proxy实现数据劫持
            let state = reactive({
                x: 1,
                y: 2
            });
            console.log(state.x, state.y);
            state.x++;
            state.y++;
            // 如果解构state对象，x和y属性失去了响应式
            // 解决方案：可以通过toRefs方法让对象每个属性都变成响应式。reactive是在reactive方法层面对它的每个属性进行拦截。toRefs是把每个属性又变成了单独的响应式对象，所以解构以后就没影响了。
            // toRef 让对象中某一项变成响应式对象
            console.log(toRef(state, x))

            // 一般开发中通过ractive创建对象，返回的时候使用toRefs
            console.log(toRefs(state))
            // toRefs只对对象的第一层拦截，如果state.x.y = 1这样，y是没有变成响应式的。但是reactive在拦截的时候会遍历到所有层级

            //给reactive使用computed
            let total = computed(() => {
                let { x, y } = state
                return x + y
            })
            return {
                ...toRefs(state)
            }


            // watchEffect
            // callback第一次加载组件执行，callback中所依赖的状态发生改变，会触发callback执行。类似于生命周期函数中mounted和updated。只不过只有更改了依赖的状态才会在更新后执行
            watchEffect(() => {
                console.log(state.x)
            })

            // watch
            // 监听现有状态改变，触发对应的函数执行
            // 第一次不会触发，只有state的属性发生任何变化，回调函数才会执行
            watch(state, () => {
                console.log()
            })
            watch(
                () => state.x, // 要监听的属性，reactive创建的state这样写，必须用函数返回，ref创建的数据可以直接写supNum
                (next, prev) => {
                    // next最新值，prev之前的值
                }
            )
            watch(
                () => state.x,
                (next, prev) => {
                    console.log()
                },
                {
                    immediate: true
                }
            )
            
            // unref 把响应式变成不响应式 unref(supNum)
            // isRef
            // isReactive
            // isReadonly

            // readonly
            // 传入一个对象（响应式或普通）或ref，返回一个原始对象的只读代理
            // 一个只读的代理是“深层的”，对象内部任何嵌套的属性也都是只读的
            const original = reactive({count: 0})
            const copy = readonly(original)


            // 获取dom
            // 给div设置ref属性的值为root
            let root = ref(null)
            onMounted(() => {
                console.log(root.value)
            })
            
        }
    }
</script>

</html>